package cn.com.easy.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;

import com.maxmind.geoip2.DatabaseReader;

/**
 * ip工具类
 * 
 * @author nibili 2016年2月25日
 * 
 */
public class IPUtils {

	/** 查找ip所在城市：新浪 */
	private static String IP_CITY_URL_FIRST = "http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=";
	/** 查找ip所在城市：淘宝 */
	private static String IP_CITY_URL_SECOND = "http://ip.taobao.com/service/getIpInfo.php?ip=";
	/** 网卡mac地址 */
	private static String macAddressStr = null;
	/** windows查ip */
	private static final String[] windowsCommand = { "ipconfig", "/all" };
	/** linux查ip */
	private static final String[] linuxCommand = { "/sbin/ifconfig", "-a" };
	/** 匹配是否mac地址 */
	private static final Pattern macPattern = Pattern.compile(".*((:?[0-9a-f]{2}[-:]){5}[0-9a-f]{2}).*", Pattern.CASE_INSENSITIVE);
	/** 读取数据库内容 */
	private static DatabaseReader reader = null;

	public static void main(String[] args) throws Exception {
		// String result = IPUtils.getCityNameByIP("58.211.8.108", 30000,
		// 30000);
		// if (StringUtils.isNotBlank(result) == true) {
		// System.out.println(result);
		// } else {
		// System.out.println("无法识别");
		// }
		//
		// System.out.println(FastJSONUtils.toJsonString(IPUtils.getRealIps()));
		//
		// System.out.println("本机MAC地址:" + getMacAddressList());

		// String path =
		// req.getSession().getServletContext().getRealPath("/WEB-INF/classes/GeoLite2-City.mmdb");

		// 访问IP
		String ip = "36.157.208.62";
		String site = IPUtils.getCountry(ip) + "-" + IPUtils.getProvince(ip) + "-" + IPUtils.getCity(ip);
		System.out.println(site);
		ip = "59.60.24.164";
		site = IPUtils.getCountry(ip) + "-" + IPUtils.getProvince(ip) + "-" + IPUtils.getCity(ip);
		System.out.println(site);
	}

	/**
	 * 
	 * @description: 获得国家
	 * @param reader
	 * @param ip
	 * @return
	 * @throws Exception
	 */
	public static String getCountry(String ip) throws Exception {
		initReader();
		return reader.city(InetAddress.getByName(ip)).getCountry().getNames().get("zh-CN");
	}

	/**
	 * 
	 * @description: 获得省份
	 * @param reader
	 * @param ip
	 * @return
	 * @throws Exception
	 */
	public static String getProvince(String ip) throws Exception {
		initReader();
		return reader.city(InetAddress.getByName(ip)).getMostSpecificSubdivision().getNames().get("zh-CN");
	}

	/**
	 * 
	 * @description: 获得城市
	 * @param reader
	 * @param ip
	 * @return
	 * @throws Exception
	 */
	public static String getCity(String ip) throws Exception {
		initReader();
		return reader.city(InetAddress.getByName(ip)).getCity().getNames().get("zh-CN");
	}

	/**
	 * 初始化离线 ip获取所属城市文件
	 * 
	 * @auth nibili 2019年12月2日 下午9:59:20
	 */
	private static void initReader() {
		try {
			if (reader == null) {
				reader = new DatabaseReader.Builder(IPUtils.class.getResourceAsStream("/GeoLite2-City.mmdb")).build();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @description: 获得经度
	 * @param reader
	 * @param ip
	 * @return
	 * @throws Exception
	 */
	public static Double getLongitude(DatabaseReader reader, String ip) throws Exception {
		return reader.city(InetAddress.getByName(ip)).getLocation().getLongitude();
	}

	/**
	 * 
	 * @description: 获得纬度
	 * @param reader
	 * @param ip
	 * @return
	 * @throws Exception
	 */
	public static Double getLatitude(DatabaseReader reader, String ip) throws Exception {
		return reader.city(InetAddress.getByName(ip)).getLocation().getLatitude();
	}

	/**
	 * 获取多个网卡地址
	 * 
	 * @return
	 * @throws IOException
	 * @author nibili 2018年2月28日
	 */
	private final static List<String> getMacAddressList() throws IOException {
		final ArrayList<String> macAddressList = new ArrayList<String>();
		final String os = System.getProperty("os.name");
		final String command[];
		if (os.startsWith("Windows")) {
			command = windowsCommand;
		} else if (os.startsWith("Linux")) {
			command = linuxCommand;
		} else {
			throw new IOException("Unknow operating system:" + os);
		}
		// 执行命令
		final Process process = Runtime.getRuntime().exec(command);
		BufferedReader bufReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
		for (String line = null; (line = bufReader.readLine()) != null;) {
			Matcher matcher = macPattern.matcher(line);
			if (matcher.matches()) {
				macAddressList.add(matcher.group(1));
				// macAddressList.add(matcher.group(1).replaceAll("[-:]",
				// ""));//去掉MAC中的“-”
			}
		}
		process.destroy();
		bufReader.close();
		return macAddressList;
	}

	/**
	 * 获取一个网卡地址（多个网卡时从中获取一个）
	 * 
	 * @return
	 * @author nibili 2018年2月28日
	 */
	public static String getLocalMac() {
		if (macAddressStr == null || macAddressStr.equals("")) {
			StringBuffer sb = new StringBuffer(); // 存放多个网卡地址用，目前只取一个非0000000000E0隧道的值
			try {
				List<String> macList = getMacAddressList();
				for (Iterator<String> iter = macList.iterator(); iter.hasNext();) {
					String amac = iter.next();
					if (!amac.equals("0000000000E0")) {
						sb.append(amac);
						break;
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			macAddressStr = sb.toString();
		}
		return macAddressStr;
	}

	/**
	 * 获取本机ip
	 * 
	 * @return
	 * @author nibili 2018年1月12日
	 */
	public static List<String> getRealIps() {
		List<String> ips = new ArrayList<String>();
		String localip = null;// 本地IP，如果没有配置外网IP则返回它
		String netip = null;// 外网IP
		Enumeration<NetworkInterface> netInterfaces;
		try {
			netInterfaces = NetworkInterface.getNetworkInterfaces();
		} catch (SocketException e) {
			return null;
		}
		InetAddress ip = null;
		boolean finded = false;// 是否找到外网IP
		while (netInterfaces.hasMoreElements() && !finded) {
			NetworkInterface ni = netInterfaces.nextElement();
			Enumeration<InetAddress> address = ni.getInetAddresses();
			while (address.hasMoreElements()) {
				ip = address.nextElement();
				if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 外网IP
					netip = ip.getHostAddress();
					ips.add(netip);
					finded = true;
					break;
				} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 内网IP
					localip = ip.getHostAddress();
					ips.add(localip);
				}
			}
		}
		return ips;
	}

	/**
	 * 根据ip获取所属城市名称
	 * 
	 * @param ipString
	 * @return
	 * @author nibili 2016年2月25日
	 * @throws Exception
	 */
	public static String getCityNameByIP(String ipString, int connectTimeOut, int readTimeOut) {
		try {
			String cityName = "";
			String temp = "";
			// 新浪
			temp = IPUtils.doGet(IP_CITY_URL_FIRST + ipString, connectTimeOut, readTimeOut);
			if (StringUtils.isNotBlank(temp) == true) {
				AreaDTO areaDTO = FastJSONUtils.toObject(temp, AreaDTO.class);
				if (areaDTO != null) {
					String city = areaDTO.getCity();
					if (StringUtils.isNotBlank(city) == true && StringUtils.endsWithAny(city, "市") == false) {
						cityName = city + "市";
					}
				}
			}
			if (StringUtils.isBlank(cityName) == true) {
				// 淘宝
				temp = IPUtils.doGet(IP_CITY_URL_SECOND + ipString, connectTimeOut, readTimeOut);
				if (StringUtils.isNotBlank(temp) == true) {
					AreaResultDTO areaResultDTO = FastJSONUtils.toObject(temp, AreaResultDTO.class);
					AreaDTO areaDTO = areaResultDTO.getData();
					if (areaDTO != null) {
						return areaDTO.getCity();
					}
				}
			}
			return cityName;
		} catch (Exception ex) {
			return "";
		}
	}

	/**
	 * 淘宝接口返回结果数据
	 * 
	 * @author nibili 2016年5月6日
	 * 
	 */
	public static class AreaResultDTO {
		private AreaDTO data;

		/**
		 * get data
		 * 
		 * @return
		 * @author nibili 2016年5月6日
		 */
		public AreaDTO getData() {
			return data;
		}

		/**
		 * set data
		 * 
		 * @param data
		 * @author nibili 2016年5月6日
		 */
		public void setData(AreaDTO data) {
			this.data = data;
		}
	}

	/** 区域dto */
	public static class AreaDTO {
		/** 国家 */
		private String country;
		/** 省 */
		private String province;
		/** 市 */
		private String city;

		/**
		 * get country
		 * 
		 * @return
		 * @author nibili 2016年5月6日
		 */
		public String getCountry() {
			return country;
		}

		/**
		 * set country
		 * 
		 * @param country
		 * @author nibili 2016年5月6日
		 */
		public void setCountry(String country) {
			this.country = country;
		}

		/**
		 * get province
		 * 
		 * @return
		 * @author nibili 2016年5月6日
		 */
		public String getProvince() {
			return province;
		}

		/**
		 * set province
		 * 
		 * @param province
		 * @author nibili 2016年5月6日
		 */
		public void setProvince(String province) {
			this.province = province;
		}

		/**
		 * get city
		 * 
		 * @return
		 * @author nibili 2016年5月6日
		 */
		public String getCity() {
			return city;
		}

		/**
		 * set city
		 * 
		 * @param city
		 * @author nibili 2016年5月6日
		 */
		public void setCity(String city) {
			this.city = city;
		}

	}

	/**
	 * 获取客户端真实ip
	 * 
	 * @param request
	 * @return
	 * @author nibili 2016年2月25日
	 */
	public static String getRealIP(HttpServletRequest request) {
		String ip = request.getHeader("X-Real-IP");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("x-forwarded-for");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || StringUtils.startsWith(ip, "0:0:0:0:0:0:0")) {
			ip = request.getRemoteHost();
		}
		return ip;
	}

	// /**
	// * unicode 转换成 中文
	// *
	// * @author fanhui 2007-3-15
	// * @param theString
	// * @return
	// */
	// private static String decodeUnicode(String theString) {
	// char aChar;
	// int len = theString.length();
	// StringBuffer outBuffer = new StringBuffer(len);
	// for (int x = 0; x < len;) {
	// aChar = theString.charAt(x++);
	// if (aChar == '\\') {
	// aChar = theString.charAt(x++);
	// if (aChar == 'u') {
	// int value = 0;
	// for (int i = 0; i < 4; i++) {
	// aChar = theString.charAt(x++);
	// switch (aChar) {
	// case '0':
	// case '1':
	// case '2':
	// case '3':
	// case '4':
	// case '5':
	// case '6':
	// case '7':
	// case '8':
	// case '9':
	// value = (value << 4) + aChar - '0';
	// break;
	// case 'a':
	// case 'b':
	// case 'c':
	// case 'd':
	// case 'e':
	// case 'f':
	// value = (value << 4) + 10 + aChar - 'a';
	// break;
	// case 'A':
	// case 'B':
	// case 'C':
	// case 'D':
	// case 'E':
	// case 'F':
	// value = (value << 4) + 10 + aChar - 'A';
	// break;
	// default:
	// throw new IllegalArgumentException("Malformed      encoding.");
	// }
	// }
	// outBuffer.append((char) value);
	// } else {
	// if (aChar == 't') {
	// aChar = '\t';
	// } else if (aChar == 'r') {
	// aChar = '\r';
	// } else if (aChar == 'n') {
	// aChar = '\n';
	// } else if (aChar == 'f') {
	// aChar = '\f';
	// }
	// outBuffer.append(aChar);
	// }
	// } else {
	// outBuffer.append(aChar);
	// }
	// }
	// return outBuffer.toString();
	// }

	/**
	 * do get
	 * 
	 * @param url
	 * @return
	 * @throws Exception
	 */
	private static String doGet(String url, int connectTimeOut, int readTimeOut) {

		String result = "";
		try {
			BufferedReader in = null;
			try {
				URL realUrl = new URL(url);
				// open connection
				URLConnection connection = realUrl.openConnection();
				connection.setConnectTimeout(connectTimeOut);
				connection.setReadTimeout(readTimeOut);
				// connect
				connection.connect();
				// define BufferedReader to read input content
				in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
				String line;
				while ((line = in.readLine()) != null) {
					result += line;
				}
			} finally {
				if (in != null) {
					in.close();
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return result;
	}
}
